using AutojsController.Config;
using AutojsController.Helpers;
using AutojsController.Services;
using AutojsController.ViewModels;
using AutojsController.Views;
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Controls.Notifications;
using Avalonia.Markup.Xaml;
using Microsoft.EntityFrameworkCore;
using SukiUI.Dialogs;
using SukiUI.Toasts;
using System;
using System.Linq;
using Serilog;
using Microsoft.Extensions.DependencyInjection;

namespace AutojsController
{
    public partial class App : Application
    {
        private readonly string SqlitDBPath = AppContext.BaseDirectory + Consts.DB_FILE_NAME;
        private IServiceProvider? provider = null;
        private readonly ILogger logger = LoggerFactory.GetLogger();

        public override void Initialize()
        {
            AvaloniaXamlLoader.Load(this);
        }

        public override void OnFrameworkInitializationCompleted()
        {
            var services = new ServiceCollection();
            services.AddDbContextFactory<DBContext>(options =>
            {
                options.UseSqlite($"Data Source={SqlitDBPath};Command Timeout=5");
                //.LogTo((log) => Debug.WriteLine(log), new[] { DbLoggerCategory.Database.Command.Name }, LogLevel.Information);
            });

            var views = ConfigureViews(services);
            this.provider = ConfigureServices(services);
            DataTemplates.Add(new ViewLocator(views));

            using (var scope = provider.CreateScope())
            {
                var dbFactory = scope.ServiceProvider.GetRequiredService<IDbContextFactory<DBContext>>();
                using var db = dbFactory.CreateDbContext();
                db.Database.Migrate();
            }

            if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
            {
                var mainWindow = new MainWindow()
                {
                    DataContext = provider.GetRequiredService<MainWindowViewModel>()
                };
                desktop.MainWindow = mainWindow;
                
                AppDomain.CurrentDomain.UnhandledException += (sender, e) =>
                {
                    var ex = e.ExceptionObject as Exception;
                    if (ex != null)
                    {
                        var mainWindowVM = mainWindow.DataContext as MainWindowViewModel;
                        mainWindowVM?.ToastManager.CreateToast().WithContent($"程序出现严重错误")
                            .OfType(NotificationType.Error).Dismiss().After(TimeSpan.FromSeconds(3))
                            .Dismiss().ByClicking().Queue();
                        logger.Error(ex, "程序出现严重错误");
                    }
                };
            }

            base.OnFrameworkInitializationCompleted();

            
        }

        private static ServiceProvider ConfigureServices(ServiceCollection services)
        {
            services.AddSingleton<ISukiToastManager, SukiToastManager>();
            services.AddSingleton<ISukiDialogManager, SukiDialogManager>();
            services.AddSingleton<PageNavigationService>();
            services.AddSingleton<SystemConfigService>();
            services.AddSingleton<MobilesService>();
            services.AddSingleton<GroupsService>();
            services.AddSingleton<ScriptsService>();

            return services.BuildServiceProvider();
        }

        private static ControllerViews ConfigureViews(ServiceCollection services)
        {
            return new ControllerViews()
                .AddView<MainWindow, MainWindowViewModel>(services)
                .AddView<MobileView, MobileViewModel>(services)
                .AddView<ScriptView, ScriptViewModel>(services)
                .AddView<GroupView, GroupViewModel>(services)
                .AddView<SystemConfigView, SystemConfigViewModel>(services)
                .AddView<ScanMobilesDialogView, ScanMobilesDialogViewModel>(services)
                .AddView<AddMobileDialogView, AddMobileDialogViewModel>(services)
                .AddView<AddOrRenameGroupDialogView, AddOrRenameGroupDialogViewModel>(services);
        }

        public T GetRequiredService<T>() where T : class
        {
            return this.provider.GetRequiredService<T>();
        }
    }
}